Skip to content

feat: rig/globals ambient call, pipeline null-skip, tsconfig baseUrl fix - #339

Merged
pelikhan merged 1 commit into
mainfrom
copilot/fix-magic-context-call
Aug 2, 2026
Merged

feat: rig/globals ambient call, pipeline null-skip, tsconfig baseUrl fix#339
pelikhan merged 1 commit into
mainfrom
copilot/fix-magic-context-call

Conversation

Copilot AI commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

call was inaccessible at module scope without destructuring from body; pipeline passed null from a failed stage into the next stage; tsconfig.json emitted a TS5102 error for the removed baseUrl option.

rig/globals — opt-in ambient workflow primitives

New entry point "rig/globals" exposes call, pipeline, and parallel as ambient functions that route through currentWorkflow() automatically. Nothing is added to "rig" — import explicitly to opt in.

import { call, pipeline } from "rig/globals";

// No body-destructuring needed; delegates to the active workflow context
const results = await pipeline(inputs, (item) => call(worker, item));

call mirrors the full WorkflowCall surface including .text(), .json(), and .workflow(). Throws with a clear message when no workflow run is active.

pipeline — null propagation across stages

When stage N returns null (agent failure), subsequent stages for that item are now skipped and null propagates to the output rather than being passed as previous to the next stage.

tsconfig.json

Removed baseUrl: "." (deprecated in TS 5.x, TS5102). The existing paths config is sufficient.

…n, fix tsconfig baseUrl

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title feat: add rig/globals with ambient call, fix pipeline null propagation, fix tsconfig baseUrl feat: rig/globals ambient call, pipeline null-skip, tsconfig baseUrl fix Aug 2, 2026
Copilot AI requested a review from pelikhan August 2, 2026 11:23
@pelikhan
pelikhan marked this pull request as ready for review August 2, 2026 13:16
@pelikhan
pelikhan merged commit 083ec24 into main Aug 2, 2026
5 checks passed
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /tdd and /codebase-design — commenting with minor suggestions, no blocking issues.

📋 Key Themes & Highlights

Key Themes

  • Type-safety cast (globals.ts:63): callImpl as unknown as WorkflowCall silences the compiler; worth replacing with an explicit structural assignment.
  • Test coverage gaps: call.text() / call.json() no-context paths are untested; the null-skip assertion doesn't pin which items were skipped.

Positive Highlights

  • ✅ Clean opt-in design: rig/globals is fully additive — nothing is changed in rig core.
  • ✅ The pipeline null-propagation fix is minimal, correct, and well-placed.
  • ✅ Good test coverage for the happy paths of all three call variants.
  • tsconfig cleanup (baseUrl removal + missing paths entries) is correct and long-overdue.
  • ✅ Documentation in dynamic-workflows.md clearly explains the new null-skip semantics.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 32.7 AIC · ⌖ 4.34 AIC · ⊞ 6.3K
Comment /matt to run again

Comment thread skills/rig/globals.ts
child: Workflow<Input, Output>,
args?: Input,
options?: WorkflowNestedOptions,
): Promise<Output> =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] The callImpl as unknown as WorkflowCall double-cast bypasses structural type checking — TypeScript cannot verify the shape is correct.

💡 Suggestion

Assign each member explicitly so TypeScript can enforce the WorkflowCall contract at the definition site:

export const call: WorkflowCall = Object.assign(callImpl, {
  text: callImpl.text,
  json: callImpl.json,
  workflow: callImpl.workflow,
});

This avoids the double cast while keeping the code just as concise.

Comment thread skills/rig/globals.ts
function requireContext(label: string): WorkflowCall {
const ctx = currentWorkflow();
if (ctx === undefined) {
throw new Error(`${label} requires an active workflow run (call inside runWorkflow or a launcher program).`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] requireContext is called on every call.text(), call.json(), and call.workflow() invocation but is never tested in isolation — only the happy path via delegation is covered.

💡 Suggestion

Add a test for each sub-method throwing when called outside a run:

it('call.text() throws outside a workflow run', async () => {
  await expect(ambientCall.text('ping')).rejects.toThrow('requires an active workflow run');
});

it('call.json() throws outside a workflow run', async () => {
  await expect(ambientCall.json('ping', s.string)).rejects.toThrow('requires an active workflow run');
});

Only call() is tested for the no-context path; the sub-methods could diverge silently.

Comment thread src/workflow.test.ts
const stage2 = vi.fn((_prev: unknown, item: number) => item);
await expect(
pipeline([1, 2, 3], (_item: number) => _item === 2 ? null : _item * 10, stage2),
).resolves.toEqual([1, null, 3]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The pipeline null-skip test verifies that stage2 is called 2 times but does not assert which items it was called with — so a bug where it skips the wrong item would pass.

💡 Suggestion

Assert the exact calls to stage2:

expect(stage2).toHaveBeenCalledWith(10, 1, 0);
expect(stage2).toHaveBeenCalledWith(30, 3, 2);
expect(stage2).not.toHaveBeenCalledWith(expect.anything(), 2, expect.anything());

This pins both the skipped item (index 1) and the values passed to the non-null stages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants